翻車清單上,沒有一條的兇手叫敏捷;每一條的兇手,都是一項沒人扛的工程責任。
昨天的檢討會散場前,白板角落留著一個沒人敢接的問題:所以答案是回去做瀑布嗎?
回答之前,先把鏡頭拉回現場。
退款功能下架兩週了。客服恢復了原本的日子:收信、後台查單、開單給財務、財務登入金流商後台操作、回信客戶,一趟平均三個工作天。財務把那筆被標記兩次的訂單慢慢調平,月底的對帳檔終於對上。看板上那條泳道清空了,救火的加班停了。
辦公室安靜下來。這種安靜很特別——不是把事情做完的安靜,是打完敗仗的安靜。
某天晚上,後端工程師關螢幕前說了一句:
「下一次,我們回去寫完整的規格書吧。開工前全部寫清楚,寫好再動工。」
沒有人笑他。這句話在那個當下,聽起來無比合理。
檢討之後,團隊的集體結論慢慢成形,大概是這樣:
我們太急著動工了;「先做再說」害死我們;需求就該先凍結,邊做邊改才會炸;敏捷不適合有金流、有外部依賴的案子;所以下一個案子,回去做瀑布——規格書、設計文件、測試計畫,一樣一樣補齊。
跟 Day 20 那五組誤解一樣,每一句單獨看都有幾分道理。合在一起,剛好是第二次翻車的完整配方。
因為這個結論跳過了一個檢驗步驟。
Day 02 說過,瀑布邏輯鏈的第一行不是步驟,是前提:
我們認為已經知道得夠多。
前提成立,Baseline、估算、承諾,後面全順;前提不成立,後面每一步都是對著猜測做精確承諾。
拿這個前提照一下退款案,照出來的結果很難看:
退款超過 7 天要財務簽核
→ Demo 那天才從客服主管口中被問出來
HTTP 200 只是受理,不是成功
→ 聯調做到一半,金流串接工程師才說出口
webhook 會重送同一筆通知
→ 上線之後,用一筆被標記兩次的訂單學到
已出貨不能直接退、發票要折讓
→ 到下架那天都還沒完全弄清楚
現在想像重來一次,開工前先關起門把規格書寫好。寫的人是誰?還是這批人。他們知道上面這些規則嗎?不知道——連需求窗口自己都沒想過要講,不是她藏,是從頭到尾沒人問到。
那寫出來的會是什麼?一份很厚、格式完整、精確描述著錯誤想像的文件。然後拿這份文件凍結需求、估算時程、簽下承諾。
Day 02 那句話原封不動適用:對著一個猜測,畫出精確的時間表。
所以「改回 Waterfall」不是答案。這個案子的規則就是得邊做邊被問出來,它天生站在「還不知道得夠多」的那一邊——這恰好是 Day 03 說敏捷擅長的地形。
等一下。在敏捷擅長的地形上,跑自稱敏捷的方法,翻車翻成這樣?
因為這個團隊跑的從來不是敏捷的方法,只是敏捷的口號。真正的問題要換一個問法。
Day 15 到 Day 19 的翻車清單,之前是按時間排的。現在換一個排法:按「缺席的責任」排。
Requirement——問題被定義過,而且跟能拍板的人定義
缺席時:一句話需求,客服要的三分鐘、後端做的 API 呼叫、
前端畫的一顆按鈕,是三個不同的功能(Day 15)
Decision——會影響別人的決定,放在別人看得到的地方
缺席時:「200 就算成功」是後端自己拍的,webhook 三方
都以為不歸自己,對齊會議被「先做再說」擋掉(Day 16、17)
Verification——有人負責證明整條路是通的
缺席時:單元測試全綠、端到端一路紅;第一筆真實退款,
是客戶替我們驗證的(Day 17)
Acceptance——動工之前,「怎樣算完成」有可檢查的判準
缺席時:做到一半才第一次問「怎樣叫退款成功」(Day 18)
Change——承諾變了,代價被重新計算、被記錄
缺席時:把 Discovery 罵成「客戶一直改」,規則浮出後
也沒人重算承諾,直接吞進時程趕工(Day 19)
注意這份清單裡沒有一個字叫敏捷。
這五項責任,瀑布有瀑布的載體:Requirement Specification、設計文件、Test Plan、驗收依據、Change Request。敏捷有敏捷的載體:Story 與那場把問題問完的對話、看得見的決策、自動化測試、Acceptance Criteria、重新排序過的 Backlog。
載體可以換,可以變輕。Day 01 就說過這個系列的底線:
Artifact 可以變輕,但它承擔的責任不能消失。
而這個團隊的狀態是:瀑布的載體丟了(因為「我們敏捷」),敏捷的載體沒接上(因為「先做再說」)。五項責任兩頭落空,懸在空中。
懸空的責任不會消失。它只是安靜地掛在那裡,等一個最貴的時間點,連本帶利倒下來。退款案的那個時間點,叫做上線。
還剩最後一塊拼圖。
同一批人,以前的案子也差不多這樣跑,怎麼以前沒翻車?
回去翻第二部就知道了。這五項責任,過去每一項都有人扛:需求沒寫清楚,有人把該問的問題自己問完;介面沒契約,有人記得對面會怎麼做;完成沒判準,有人知道驗收那天客戶會皺哪種眉頭;決策沒紀錄,反正原作者還在。
全部是同一個人。
這一次,他被借調去救另一個專案,整段不在。責任沒有被轉移到流程上,也沒有被分給其他人——它跟著他一起離開,然後在整合日落地摔碎。
所以標題那句話,現在可以講完整了:這個團隊的問題從來不是「太敏捷」,而是五項基本工程責任長期外包給一個人的腦袋,這次連那顆腦袋都不在場。
翻車清單不是敏捷的罪狀。它是責任的缺席名單。
第三部最後一次檢查,這次結算全案總帳:
Scope □ 一項都沒少做,最後用「下架」全數歸零——不是交換,是報廢
Time ■ 上線延期;整合與返工的時間沒人估過,因為從來沒被估進去
Cost □ 預算一毛沒加;加班沒有記帳,那筆錢記在最下面那格
Quality ■ 「退款成功」但錢沒回、一筆訂單標記兩次、對帳對不上
Risk □ Day 15 起堆的未爆彈已全數兌現,帳轉列上面兩格
人 ■ 全隊救火,客服替系統道歉,財務替系統補帳 ← 結算日到了
Day 15 說過,那時的代價還沒兌現,帳單稍後寄達。
這就是那張帳單。
第三部收工,留下一張底線清單。它不挑方法——不管下一個案子打算怎麼跑,這五格都得先有人認領:
□ Requirement:問題被定義過,而且是跟能拍板的人定義的
(本案缺席時:一句話需求,每個人用自己的想像補完)
□ Decision:會影響別人的決定,放在別人看得到的地方
(本案缺席時:200 當成功自己拍板,webhook 三方互踢)
□ Verification:有人證明整條路是通的,不只自己那段是好的
(本案缺席時:單元測試全綠,真實退款由客戶代測)
□ Acceptance:動工之前,「怎樣算完成」有可檢查的判準
(本案缺席時:做到一半才第一次問怎樣叫退款成功)
□ Change:承諾改變時,代價被重新計算、被記錄
(本案缺席時:規則浮出後沒人重算承諾,直接吞進時程)
五格都有人認領,跑瀑布或跑敏捷都行;有一格沒人認領,跑什麼方法,都會在那一格漏水。
方法可以選,載體可以換;責任沒人扛的時候,它不會消失,只會挑一個最貴的時間點落地。
第三部到此為止。翻車看完了,殘骸也清點完了。
接下來只剩一件事:同一個專案、同一批人、資深工程師依然被借調不在——重新來一次。
第四部明天開始。第一步不是打開編輯器,不要 Coding。先回答一個問題:這個需求,到底誰真的能決定?